home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Special 26 / AMIGAplus Sonderheft 26 (2000)(Falke)(DE)(Track 1 of 2)[!].iso / Tools / Packer / xfd / Developer / Sources / C / UNIX-Compress.c < prev   
C/C++ Source or Header  |  1999-03-29  |  9KB  |  320 lines

  1. unsigned char version[] = "$VER: UNIX-Compress 1.2 (04.08.1998) by SDI";
  2.  
  3. /* Objectheader
  4.  
  5.     Name:        UNIX-Compress.c
  6.     Description:    xfd external decruncher for UNIX compress files
  7.     Author:        SDI (stoecker@amigaworld.com)
  8.     Distribution:    PD
  9.  
  10.  1.0   22.12.97 : first version
  11.  1.1   23.12.97 : added memory expansion
  12.  1.2   04.08.98 : bug fix for block compress, added internal SysBase
  13. */
  14.  
  15. /* Because there is no way to find out the size of uncrunched file, this
  16.    routine uses a destination buffer, which is 4 times as large as the
  17.    source file. When there is not enough memory, the largest memory block
  18.    is used.
  19.    This does surely not cover all Compress files! So there may be some
  20.    which cannot be decrunched. XPKERR_CORRUPTEDDATA should be reported for
  21.    these. In this case the program tries to allocate the largest available
  22.    memory block and restarts decrunching.
  23.  
  24.    Has anyone a better idea how to find out destination length?
  25. */
  26.  
  27.  
  28. #include <libraries/xfdmaster.h>
  29. #include <proto/exec.h>
  30. #include <exec/memory.h>
  31.  
  32. #ifdef __MAXON__
  33.   #define __asm
  34. #endif
  35.  
  36. #define MAXCODE(n)    (((ULONG) 1 << (n)) - 1)
  37.  
  38. #define BITS           16
  39. #define STACKSIZE     8000
  40. #define FIRST          257        /* first free entry */
  41. #define CLEAR          256        /* table clear output code */
  42. #define INIT_BITS        9        /* initial number of bits/code */
  43.  
  44. /* Defines for third byte of header */
  45. #define BIT_MASK    0x1f
  46. #define BLOCK_MASK    0x80
  47. #define LZW_RESERVED    0x60
  48.     /* Masks 0x40 and 0x20 are free. I think 0x20 should mean that
  49.        there is a fourth header byte (for expansion). */
  50.  
  51. UBYTE rmask[9] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
  52.  
  53. LONG decomp(struct CompressData *, STRPTR, ULONG, STRPTR, ULONG);
  54. LONG getcode(struct CompressData *);
  55.  
  56. struct CompressData {
  57.   UWORD      block_compress;
  58.   WORD        clear_flg;
  59.   UWORD        n_bits;            /* number of bits/code */
  60.   UWORD      maxbits;        /* user settable max # bits/code */
  61.   ULONG     maxcode;        /* maximum code, given n_bits */
  62.   ULONG     maxmaxcode;
  63.   LONG         free_ent;
  64.   LONG        offset;
  65.   LONG        size;
  66.   STRPTR    inptr;            /* current input pointer */
  67.   STRPTR    inendptr;        /* end of input buffer */
  68.   UWORD *    tab_prefixof;
  69.   STRPTR     tab_suffixof;
  70.   STRPTR     stack;
  71.   UBYTE        buf[BITS];
  72. };
  73.  
  74. /************** Here starts xfd stuff - the xfdSlave structure **********/
  75.  
  76. #define MASTER_VERS    36
  77.  
  78. typedef BOOL (*xfdFunc) ();
  79.  
  80. LONG __asm RecogCompress(register __a0 STRPTR buf, register __d0 ULONG length);
  81. BOOL __asm DecrunchCompress(register __a0 struct xfdBufferInfo * xbi,
  82. register __a6 struct xfdMasterBase *xfdMasterBase);
  83.  
  84. struct xfdSlave FirstSlave = {
  85.   0, XFDS_VERSION, MASTER_VERS, "UNIX Compress", XFDPFF_DATA, 0, 
  86.   (xfdFunc) RecogCompress, (xfdFunc) DecrunchCompress, 0, 0, 0, 0, 4};
  87.  
  88. LONG __asm RecogCompress(register __a0 STRPTR buf, register __d0 ULONG length)
  89. {
  90.   if(*((UWORD *)buf) == 0x1F9D)
  91.   {
  92.     UBYTE mb = buf[2];
  93.     if(mb & LZW_RESERVED)        /* Unknown format */
  94.       return 0;
  95.     if((mb & BIT_MASK) > BITS)        /* Too much bits */
  96.       return 0;
  97.     return 1;    /* Now should be a correct file */
  98.   }
  99.   return 0;
  100. }
  101.  
  102. BOOL __asm DecrunchCompress(register __a0 struct xfdBufferInfo * xbi,
  103. register __a6 struct xfdMasterBase *xfdmasterBase)
  104. {
  105.   struct CompressData cd;
  106.   LONG ret = -XFDERR_NOMEMORY;
  107.   ULONG maxmaxcode = 1<<((((STRPTR)xbi->xfdbi_SourceBuffer)[2])&BIT_MASK);
  108.   struct ExecBase *SysBase;
  109.  
  110.   SysBase = xfdmasterBase->xfdm_ExecBase;
  111.  
  112.   if((cd.tab_prefixof = (UWORD *) AllocMem(sizeof(UWORD)*maxmaxcode, MEMF_ANY)))
  113.   {
  114.     if((cd.stack = (STRPTR) AllocMem(STACKSIZE, MEMF_ANY)))
  115.     {
  116.       if((cd.tab_suffixof = (STRPTR) AllocMem(maxmaxcode, MEMF_ANY)))
  117.       {
  118.         ULONG bufsize;
  119.  
  120.     bufsize = AvailMem(MEMF_LARGEST|xbi->xfdbi_TargetBufMemType);
  121.  
  122.         if((xbi->xfdbi_TargetBufLen = xbi->xfdbi_SourceBufLen<<2) > bufsize)
  123.           xbi->xfdbi_TargetBufLen = bufsize;
  124.  
  125.         if((xbi->xfdbi_TargetBuffer = AllocMem(xbi->xfdbi_TargetBufLen,
  126.         xbi->xfdbi_TargetBufMemType)))
  127.         {
  128.           if((ret = decomp(&cd, (STRPTR) xbi->xfdbi_SourceBuffer,
  129.           xbi->xfdbi_SourceBufLen, (STRPTR) xbi->xfdbi_TargetBuffer,
  130.           xbi->xfdbi_TargetBufLen)) > 0)
  131.             xbi->xfdbi_TargetBufSaveLen = ret;
  132.           else
  133.           {
  134.             FreeMem(xbi->xfdbi_TargetBuffer, xbi->xfdbi_TargetBufLen);
  135.             if(bufsize != xbi->xfdbi_TargetBufLen)
  136.             {
  137.           /* expand memory to full available and retry */
  138.               xbi->xfdbi_TargetBufLen = AvailMem(MEMF_LARGEST|xbi->xfdbi_TargetBufMemType);
  139.               if((xbi->xfdbi_TargetBuffer = AllocMem(xbi->xfdbi_TargetBufLen,
  140.               xbi->xfdbi_TargetBufMemType)))
  141.               {
  142.                 if((ret = decomp(&cd, (STRPTR) xbi->xfdbi_SourceBuffer,
  143.                 xbi->xfdbi_SourceBufLen, (STRPTR) xbi->xfdbi_TargetBuffer,
  144.                 xbi->xfdbi_TargetBufLen)) > 0)
  145.                   xbi->xfdbi_TargetBufSaveLen = ret;
  146.                 else
  147.                   FreeMem(xbi->xfdbi_TargetBuffer, xbi->xfdbi_TargetBufLen);
  148.               }
  149.             }
  150.           }
  151.         }
  152.  
  153.         FreeMem(cd.tab_suffixof, maxmaxcode);
  154.       }
  155.       FreeMem(cd.stack, STACKSIZE);
  156.     }
  157.     FreeMem(cd.tab_prefixof, sizeof(UWORD)*maxmaxcode);
  158.   }
  159.  
  160.   if(ret <= 0)
  161.   {
  162.     xbi->xfdbi_TargetBufLen = xbi->xfdbi_TargetBufSaveLen = 0;
  163.     xbi->xfdbi_TargetBuffer = 0;
  164.     xbi->xfdbi_Error = -ret;
  165.     return 0;
  166.   }
  167.  
  168.   return (BOOL) ret;
  169. }
  170.  
  171. /* Decompress. This routine adapts to the codes in the file building the
  172.  * "string" table on-the-fly; requiring no table to be stored in the
  173.  * compressed file.
  174.  */
  175.  
  176. /* negative values are error codes, positive value is resulting size */
  177. LONG decomp(struct CompressData *cd, STRPTR inbuf, ULONG insize,
  178. STRPTR outbuf, ULONG outsize)
  179. {
  180.   LONG finchar, code, oldcode, incode, blockcomp;
  181.   STRPTR outptr = outbuf, stackp = cd->stack,
  182.   stack = cd->stack, outend = outbuf+outsize;
  183.  
  184.   cd->maxbits = inbuf[2];
  185.   blockcomp = cd->block_compress = cd->maxbits & BLOCK_MASK;
  186.   cd->maxbits &= BIT_MASK;
  187.   cd->maxmaxcode = 1 << cd->maxbits;
  188.   cd->maxcode = MAXCODE(cd->n_bits = INIT_BITS);
  189.   cd->free_ent = ((cd->block_compress) ? FIRST : 256);
  190.   cd->clear_flg = cd->offset = cd->size = 0;
  191.   cd->inptr = inbuf+3;
  192.   cd->inendptr = inbuf+insize;
  193.  
  194.   /* Initialize the first 256 entries in the table. */
  195.   for(code = 255; code >= 0; code--)
  196.   {
  197.     cd->tab_prefixof[code] = 0;
  198.     cd->tab_suffixof[code] = (UBYTE) code;
  199.   }
  200.  
  201.   if((finchar = oldcode = getcode(cd)) == -1)    /* EOF already ? */
  202.     return -XFDERR_CORRUPTEDDATA;        /* Get out of here */
  203.   *(outptr++) = (UBYTE) finchar; /* first code must be 8 bits = UBYTE */
  204.  
  205.   while((code = getcode(cd)) > -1)
  206.   {
  207.     if((code == CLEAR) && blockcomp)
  208.     {
  209.       for(code = 255; code >= 0; code--)
  210.     cd->tab_prefixof[code] = 0;
  211.       cd->clear_flg = 1;
  212.       cd->free_ent = FIRST - 1;
  213.       if((code = getcode(cd)) == -1)
  214.     break;                    /* O, untimely death! */
  215.     }
  216.     incode = code;
  217.  
  218.     /* Special case for KwKwK string. */
  219.     if(code >= cd->free_ent)
  220.     {
  221.       *stackp++ = finchar;
  222.       code = oldcode;
  223.     }
  224.  
  225.     /* Generate output characters in reverse order */
  226.     while(code >= 256)
  227.     {
  228.       *stackp++ = cd->tab_suffixof[code];
  229.       code = cd->tab_prefixof[code];
  230.     }
  231.     *stackp++ = finchar = cd->tab_suffixof[code];
  232.  
  233.     if(stackp - stack > outend - outptr) /* buffer was to short :-( */
  234.       return -XFDERR_CORRUPTEDDATA;
  235.  
  236.     /* And put them out in forward order */
  237.     do
  238.     {
  239.       *(outptr++) = *(--stackp);
  240.     } while(stackp > stack);
  241.  
  242.     /* Generate the new entry. */
  243.     if((code = cd->free_ent) < cd->maxmaxcode)
  244.     {
  245.       cd->tab_prefixof[code] = (UWORD) oldcode;
  246.       cd->tab_suffixof[code] = finchar;
  247.       cd->free_ent = code+1;
  248.     }
  249.     /* Remember previous code. */
  250.     oldcode = incode;
  251.   }
  252.   return (outptr-outbuf);
  253. }
  254.  
  255. /* Read one code from input. If EOF, return -1. */
  256. LONG getcode(struct CompressData *cd)
  257. {
  258.   LONG code, r_off, bits;
  259.   UBYTE *bp = cd->buf;
  260.  
  261.   if(cd->clear_flg > 0 || cd->offset >= cd->size || cd->free_ent > cd->maxcode)
  262.   {
  263.     /*
  264.      * If the next entry will be too big for the current code
  265.      * size, then we must increase the size.  This implies reading
  266.      * a new buffer full, too.
  267.      */
  268.     if(cd->free_ent > cd->maxcode)
  269.     {
  270.       if(++cd->n_bits == cd->maxbits)
  271.     cd->maxcode = cd->maxmaxcode;    /* won't get any bigger now */
  272.       else
  273.     cd->maxcode = MAXCODE(cd->n_bits);
  274.     }
  275.     if(cd->clear_flg > 0)
  276.     {
  277.       cd->maxcode = MAXCODE(cd->n_bits = INIT_BITS);
  278.       cd->clear_flg = 0;
  279.     }
  280.  
  281.     if(cd->inendptr <= cd->inptr)
  282.       return -1;            /* end of file */
  283.  
  284.     /* This reads maximum n_bits characters into buf */
  285.     cd->size = 0;
  286.     while(cd->size < cd->n_bits && cd->inptr < cd->inendptr)
  287.       cd->buf[cd->size++] = *(cd->inptr++);
  288.  
  289.     cd->offset = 0;
  290.     /* Round size down to integral number of codes */
  291.     cd->size = (cd->size << 3) - (cd->n_bits - 1);
  292.   }
  293.   r_off = cd->offset;
  294.   bits = cd->n_bits;
  295.  
  296.   /* Get to the first byte. */
  297.   bp += (r_off >> 3);
  298.   r_off &= 7;
  299.  
  300.   /* Get first part (low order bits) */
  301.   code = (*bp++ >> r_off);
  302.   bits -= (8 - r_off);
  303.   r_off = 8 - r_off;            /* now, offset into code word */
  304.  
  305.   /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
  306.   if(bits >= 8)
  307.   {
  308.     code |= *bp++ << r_off;
  309.     r_off += 8;
  310.     bits -= 8;
  311.   }
  312.  
  313.   /* high order bits. */
  314.   code |= (*bp & rmask[bits]) << r_off;
  315.   cd->offset += cd->n_bits;
  316.  
  317.   return code;
  318. }
  319.  
  320.